# -*- mode: python -*-
###
#
# (c) 2000-2007 Wijnand Modderman <wijnand at tehmaze dot com>
# All rights reserved. See docs/LICENSE
#
###

__revision__ = '$Hg: db.py,v 0f20732e7e4b 2007/01/21 15:36:53 +0100 $'

# system imports
import sqlalchemy as sql

# DDB imports
from ddb.config import configFile
from ddb.log import log

# Twisted imports

class DBException(Exception):
    pass

class IDBConnector:
    """I maintain a stack of database connections by their DSN."""
    connections = {}
    tables      = {}

    def connect(self, dsn):
        if not self.connections.has_key(dsn):
            log.msg('DB Connecting to %s' % dsn, debug=True)
            self.connections[dsn] = sql.BoundMetaData(dsn)
        else:
            log.msg('DB Recycling %s' % dsn, debug=True)
        return self.connections[dsn]

    def table(self, meta, tableName, layout):
        if not self.tables.has_key(tableName):
            table = sql.Table(tableName, meta, *layout)
            self.tables[tableName] = table
            self.tables[tableName].create(checkfirst=True)
        return self.tables[tableName]

DBConnector = IDBConnector() # initialize a pool of connections

class DB:
    config = None   # a ddb.config.configFile instance to configure from
    driver = None   # either 'disk' or 'memory'
    layoyt = {}     # dict with tables, with their name as key, and their
                    # structure as value

    def __init__(self, config='config/db.ini'):
        """Initialise a database, first read configuration from C<config>,
        if this is a string, a new configFile object will be created."""
        if not self.driver or not hasattr(self, 'connect_%s' % self.driver):
            raise DBException, "no valid driver specified"
        if config:
            if isinstance(config, configFile):
                self.config = config
            else:
                self.config = configFile(config)
            self.config.load()
        connector = getattr(self, 'connect_%s' % self.driver)
        connector()
        self.setup_tables()

    def connect_memory(self):
        self.dsn  = 'sqlite:///:memory:'
        self.meta = DBConnector.connect(self.dsn)

    def connect_disk(self):
        try:
            self.dsn = self.config.get('database', 'dsn')[0]
        except ValueError:
            raise DBException('No dsn configured in database section of "%s"' % self.config.file)
        self.meta = DBConnector.connect(self.dsn)

    def select(self, tableName, *args, **kwargs):
        return self.tables[tableName].select(*args, **kwargs)

    def setup_tables(self):
        self.tables = {}
        for tableName in self.layout.keys():
            # Recycle tables, yes, if you change your schema, remove the table, reboot
            self.tables[tableName] = DBConnector.table(self.meta, tableName, self.layout[tableName])

    def table(self, tableName):
        return self.tables[tableName]

__all__ = ['sql', 'DB']

# vim:ts=4:sw=4:et:
